#include "cmsisDapHid.h"

#include <hidapi.h>

#include <string.h>
#include <stdlib.h>

#define REPORT_ID_SIZE   1

cmsisDapHid::cmsisDapHid()
{
    _dev = 0;
}

cmsisDapHid::~cmsisDapHid()
{

}

int cmsisDapHid::open(const char *devname)
{
    struct hid_device_info *devs, *cur_dev;
    hid_device *dev = NULL;

    if (hid_init() != 0)
    {
        return -1;
    }

    devs = hid_enumerate(0x0, 0x0);
    cur_dev = devs;
    while (cur_dev)
    {
        bool found = false;

        if (cur_dev->product_string)
        {
            if (wcsstr(cur_dev->product_string, L"CMSIS-DAP"))
            {
                found = true;
            }
        }

        if (found)
        {
            break;
        }

        cur_dev = cur_dev->next;
    }

    if (!cur_dev)
    {
        hid_free_enumeration(devs);
        return -1;
    }

    dev = hid_open_path(cur_dev->path);
    hid_free_enumeration(devs);

    if (!dev)
    {
        return -1;
    }

    this->_dev = dev;

    return 0;
}

void cmsisDapHid::close()
{
    if (this->_dev)
    {
        hid_close((hid_device*)this->_dev);
        this->_dev = nullptr;
        hid_exit();
    }
}

int cmsisDapHid::read(struct cmsis_dap *dap, int timeout_ms)
{
    int retval = hid_read_timeout((hid_device*)this->_dev, dap->packet_buffer, dap->packet_buffer_size, timeout_ms);

    if (retval == 0) {
        return -6;
    } else if (retval == -1) {
        return -1;
    }

    return retval;
}

int cmsisDapHid::write(struct cmsis_dap *dap, int txlen, int timeout_ms)
{
    (void) timeout_ms;

    dap->packet_buffer[0] = 0; /* HID report number */

    /* Pad the rest of the TX buffer with 0's */
    memset(dap->command + txlen, 0, dap->packet_size - txlen);

    /* write data to device */
    int retval = hid_write((hid_device*)this->_dev, dap->packet_buffer, dap->packet_buffer_size);
    if (retval == -1) {
        return -1;
    }

    return retval;
}

int cmsisDapHid::packet_buffer_alloc(struct cmsis_dap *dap, unsigned int pkt_sz)
{
    unsigned int packet_buffer_size = pkt_sz + REPORT_ID_SIZE;
    uint8_t *buf = (uint8_t*)malloc(packet_buffer_size);
    if (!buf) {
        return -1;
    }

    dap->packet_buffer = buf;
    dap->packet_size = pkt_sz - REPORT_ID_SIZE;
    dap->packet_buffer_size = packet_buffer_size;

    dap->command = dap->packet_buffer + REPORT_ID_SIZE;
    dap->response = dap->packet_buffer;

    return 0;
}
